#include <stdio.h>
#include <string.h>
#include "symtab.h"
#include "parser.h"
#include "keywords.h"

#define MAXSYMTBENTRIES 0x10000
int symtab[MAXSYMTBENTRIES][10];
int symtab_nextentry = 1;

#define MAXLEXTAPESIZ   0x100000
char lextape[MAXLEXTAPESIZ];
int lextape_nextentry = 0;

/*
 * Symbols in symtab:
 * 
 * 0 - symbol
 * 1 - object type
 * 2 - datatype
 * 3 - offset/label number
 * 4 - label is used
 * 5 - number of parameters
 * 6 - parameter 1
 * 7 - parameter 2
 * 8 - parameter 3
 * 9 - parameter 4
 * 
 * 
 */

int symtab_insert(char const *symbol, int otype, int dtype,int offset,int numParms)
{
  if(symtab_nextentry == MAXSYMTBENTRIES){
    fprintf(stderr,"ERROR: Symtab Overflow!\n");
    errFlag = SEMANTICERR;
    return -1;
  }else{
    symtab[symtab_nextentry][0] = lextape_nextentry;
    symtab[symtab_nextentry][1] = otype;
    symtab[symtab_nextentry][2] = dtype;
    symtab[symtab_nextentry][3] = offset;
    symtab[symtab_nextentry][4] = 0;
    symtab[symtab_nextentry][5] = numParms;
    strcpy(lextape + lextape_nextentry,symbol);
    lextape_nextentry += strlen(symbol) + 1;
    return symtab_nextentry++;
  }
}

int symtab_lookup(char const *symbol)
{
  int i;
  for(i=symtab_nextentry-1;i>0; i--){
    if(strcmp(lextape+symtab[i][0],symbol)==0) return i;
  }
  return 0;
}

void symtab_removelocals(int symbol_entry,int *sympos){
  *sympos = 0;
  int i = symbol_entry-1;
  int j = symbol_entry;
  symtab_nextentry = symbol_entry+1;
  
  if(i >= 0){
    while(symtab[i][1] == PARMTYPE){
      symtab[i][0] = symtab[j][0];
      symtab[i][1] = symtab[j][1];
      symtab[i][2] = symtab[j][2];
      symtab[i][3] = symtab[j][3];
      symtab[i][4] = symtab[j][4];
      symtab[i][5] = symtab[j][5];
      symtab[i][6] = symtab[j][6];
      symtab[i][7] = symtab[j][7];
      symtab[i][8] = symtab[j][8];
      symtab[i][9] = symtab[j][9];
      i--;
      j--;
      symtab_nextentry--;
    }
  }
}

char* symtab_getSymbol(int symbol_entry){
  return lextape+symtab[symbol_entry][0];
}

int symtab_getNextEntry(){
   return symtab_nextentry;
}

void symtab_setNextEntry(int nextEntry){
   symtab_nextentry = nextEntry;
}

int symtab_getOtype(int symbol_entry){
  return symtab[symbol_entry][1];
}

int symtab_getDtype(int symbol_entry){
  return symtab[symbol_entry][2];
}

void symtab_setDtype(int symbol_entry,int dtype_value){
   symtab[symbol_entry][2] = dtype_value;
}

int symtab_getOffset(int symbol_entry){
  return symtab[symbol_entry][3];
}

void symtab_setOffset(int symbol_entry,int offset_value){
   symtab[symbol_entry][3] = offset_value;
}

int symtab_getLblNbr(int symbol_entry){
  return symtab[symbol_entry][3];
}

void symtab_setLblNbr(int symbol_entry,int lbl_value){
   symtab[symbol_entry][3] = lbl_value;
}

int symtab_getLabelUsed(int symbol_entry){
  return symtab[symbol_entry][4];
}

void symtab_setLabelUsed(int symbol_entry,int labelUsed){
   symtab[symbol_entry][4] = labelUsed;
}

int symtab_getNumParms(int symbol_entry){
  return symtab[symbol_entry][5];
}

void symtab_setNumParms(int symbol_entry,int numParms){
   symtab[symbol_entry][5] = numParms;
}

int symtab_getParm(int symbol_entry,int numParm){
  return symtab[symbol_entry][numParm+5];
}

void symtab_setParm(int symbol_entry,int numParm,int parm){
  symtab[symbol_entry][numParm+5] = parm;
}

void print_symtab(void){
  int i;
  printf("symbol table:\n");
  
  for(i=1;i < symtab_nextentry; i++){
    printf("symbol: %s",(lextape+symtab[i][0]));
    switch(symtab[i][1]){
      case VARTYPE: printf(" - objtype: VAR");
		    break;
      case PROCTYPE: printf(" - objtype: PROCEDURE");
		     break;
      case FUNCTYPE: printf(" - objtype: FUNCTION");
		     break;
      case PARMTYPE: printf(" - objtype: PARAMETER");
		     break;
      case LBLTYPE: printf(" - objtype: LABEL");
		     break;
      case CNSTTYPE: printf(" - objtype: CONSTANT");
		     break;
      case TYPTYPE: printf(" - objtype: TYPE");
		     break;
    }
    switch(symtab[i][2]){
      case INTEGER: printf(" - datatype: INTEGER");
		    break;
      case REAL: printf(" - datatype: REAL");
		 break;
      case STRING: printf(" - datatype: STRING");
		 break;
      case BOOLEAN: printf(" - datatype: BOOLEAN");
		 break;
    }
    printf(" - offset: %d\n",symtab[i][3]);
    switch(symtab[i][1]){
      case LBLTYPE: 
	if(symtab[i][4]) printf(" - isUsed: TRUE\n");
	else printf(" - isUsed: FALSE\n");
	break;
      case PROCTYPE:
      case FUNCTYPE:
	printf(" - numParms: %d",symtab[i][5]);
	if(!symtab[i][5]) printf("\n");
	int j;
	for(j = 0;j < symtab[i][5];j++){
	  switch(symtab[i][j+6]){
	    case INTEGER: printf(" - parm%d: INTEGER",j+1);
			  break;
	    case REAL: printf(" - parm%d: REAL",j+1);
		      break;
	    case STRING: printf(" - parm%d: STRING",j+1);
		      break;
	    case BOOLEAN: printf(" - parm%d: BOOLEAN",j+1);
		      break;
	  }
	}
	if(symtab[i][5]) printf("\n");
	break;
    }
      
  }
}